package com.aliyun.tiangong.exception;

import com.aliyun.tiangong.constant.TiangongConstant;
import com.aliyun.tiangong.support.RestResult;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.AbstractErrorController;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;

/**
 * @author xinghen
 * @ClassName: GlobalExceptionHandler
 * @Package: com.aliyun.tiangong.exception
 * @Description 全局异常处理器
 * @create 2018/04/20 06:38
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class GlobalExceptionController extends AbstractErrorController {

    private static final String ERROR_PAGE_PREFIX = "error/error-";

    @Value("${server.error.path:${error.path:/error}}")
    private static final String ERROR_PATH = "/error";

    public GlobalExceptionController(ErrorAttributes errorAttributes) {
        super(errorAttributes);
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request) throws Exception {
        RestResult<Object> restResult = wrapException(request);
        if (isJsonRequest(request)) {
            Map<String, Object> map = restResult.toMap();
            return new ModelAndView("jsonView", map);
        }
        String errorPage = ERROR_PAGE_PREFIX + (Objects.equals(restResult.getStatus(), 404) ? "404" : "500");
        return new ModelAndView(errorPage, Maps.newHashMap());
    }

    @RequestMapping
    @ResponseBody
    public Object handleError(HttpServletRequest request) {
        return wrapException(request);
    }

    /**
     * 抛出异常的请求是否为json请求(是否是以".json"格式结尾的)
     *
     * @param request
     * @return
     */
    private boolean isJsonRequest(HttpServletRequest request) {
        Map<String, Object> errorAttributes = getErrorAttributes(request, false);
        String uri = (String) errorAttributes.get("path");
        return StringUtils.endsWith(uri, TiangongConstant.JSON_URL_SUFFIX);
    }

    /**
     * 异常包装为RestResult
     *
     * @param request
     * @return
     */
    private RestResult<Object> wrapException(HttpServletRequest request) {
        Map<String, Object> errorAttributes = getErrorAttributes(request, false);
        Integer statusCode = (Integer) errorAttributes.get("status");
        String message;
        switch (statusCode) {
            case 401:
                message = "无权限访问";
                break;
            case 404:
                message = "您请求的URL不存在";
                break;
            default:
                message = RestResult.ERROR_MESSAGE;
        }
        return RestResult.error(statusCode, message);
    }
}
